#include <Memory/Heap.h>
#include <Memory/Paging.h>
#include <IntExcept/Debug.h>
#include <ProcessThread/ProcessThread.h>
#include <IntExcept/Error.h>
/*
@brief 初始化内核的 Arena 描述符及 Arena
@param `lpArenaDescriptor` 指向 Arena 描述符的指针
@return 状态码
@note `wszUnit` 存放 Arena 分配单元大小，必须符合 Arena 分配单元规定。
    当该值小于 `4096` 时，初始化 Arena 描述符的 `wAvailableUnits` 和 `lpArena` 字段。
    当该值等于 `4096` 时，`wAvailableUnits` 中需指定堆所需的页面数量。
*/
BOOL InitializeArenaForKernel(LPArenaDescriptor lpArenaDescriptor)
{
    KERNEL_ASSERT(lpArenaDescriptor->wGranularity <= 4096 && lpArenaDescriptor->wGranularity % 16 == 0, "Illegal arena granularity.\r\n");
    lpArenaDescriptor->lpArena = NULL; /* 描述符中保存的指向 Arena 的指针也要设置 */
    if (lpArenaDescriptor->wGranularity < 4096) /* 非超大堆内存块 */
    {
        lpArenaDescriptor->lpArena = AllocatePageForKernel(1, PTE_WRITEABLE);
        KERNEL_ASSERT(GetLastError() == ERROR_SUCCESS, "Fails to allocate heap memory for kernel.\r\n"); /* 内核请求堆内存必须成功 */
        LPDWORD lpBitmap = lpArenaDescriptor->lpArena; /* 位图 */
        switch (lpArenaDescriptor->wGranularity)
        {
        case 16:
            lpArenaDescriptor->wAvailableUnits = (PAGE_SIZE - MAX(ARENA16_BITMAP_SIZE, 16)) / 16;
            lpBitmap[0] = 0xFFFFFFFC;
            for (int i = 1; i < ARENA16_BITMAP_SIZE / sizeof(DWORD); i++)
                lpBitmap[i] = 0xFFFFFFFF;
            break;
        case 32:
            lpArenaDescriptor->wAvailableUnits = (PAGE_SIZE - MAX(ARENA32_BITMAP_SIZE, 32)) / 32;
            lpBitmap[0] = 0xFFFFFFFE;
            for (int i = 1; i < ARENA32_BITMAP_SIZE / sizeof(DWORD); i++)
                lpBitmap[i] = 0xFFFFFFFF;
            break;
        case 64:
            lpArenaDescriptor->wAvailableUnits = (PAGE_SIZE - MAX(ARENA64_BITMAP_SIZE, 64)) / 64;
            lpBitmap[0] = 0xFFFFFFFE;
            lpBitmap[1] = 0xFFFFFFFF;
            break;
        case 128:
            lpArenaDescriptor->wAvailableUnits = (PAGE_SIZE - MAX(ARENA128_BITMAP_SIZE, 128)) / 128;
            lpBitmap[0] = 0xFFFFFFFE;
            break;
        /* unit 大于 256 时位图即 wAvailableUnits */
        case 256:
            lpArenaDescriptor->wAvailableUnits = 0xFFFF; /* 16 bits */
            break;
        case 512:
            lpArenaDescriptor->wAvailableUnits = 0xFF; /* 8 bits */
            break;
        case 1024:
            lpArenaDescriptor->wAvailableUnits = 0xF; /* 4 bits */
            break;
        case 2048:
            lpArenaDescriptor->wAvailableUnits = 0x3; /* 2 bits */
            break;    
        }
    }
    else /* 4096，wcAvailable 指定数量 */
    {
        KERNEL_ASSERT(lpArenaDescriptor->wAvailableUnits != 0, "Illegal wAvailableUnits value for 4096 B arena.\r\n");
        lpArenaDescriptor->lpArena = AllocatePageForKernel(lpArenaDescriptor->wAvailableUnits, PTE_WRITEABLE);
        KERNEL_ASSERT(GetLastError() == ERROR_SUCCESS, "Fails to allocate virtual pages for kernel.\r\n"); /* 内核请求堆内存必须成功 */
    }
    return TRUE;
}